package com.shujia

import java.io.{BufferedReader, FileReader}
import java.sql.{Connection, DriverManager, PreparedStatement, ResultSet}
import scala.io.{BufferedSource, Source}

object Demo01Base {
  def main(args: Array[String]): Unit = {
    /**
     * 基础语法：
     * 变量：变量的定义、命名规则
     * 注释
     * 打印的方法：println
     * 基本数据类型：Byte、Short、Int、Long、Float、Double、Char、Boolean
     * 运算：算术运算、逻辑运算
     * 选择循环结构
     * 函数的定义
     * 类
     *
     * 面向函数编程
     */

    /**
     * 变量的定义：可变还是不可变
     * val ：不可变，相当于Java中用final修饰
     * var ：可变的，定义之后可以重新赋值
     * 尽可能使用val修饰变量
     * 命名规则类似Java：只能是大小写字母、数字、下划线，不能以数字开头，不能是关键字
     */
    // 定义一个Int类型的变量i
    val i = 10 // 在Scala中定义变量不需要声明类型，会自动进行推断
    // 也可手动声明类型（规范）
    val j: Int = 100 // 每一行代码可以用分号;结尾 ，也可以省略

    //    i = 200 // 如果需要对一个变量进行重新赋值（赋同类型的值） 那么需要在定义时用var进行修饰

    var k: Int = 20
    println(k)
    k = 2000
    println(k)

    /**
     * 当一个变量指向数据容器时（集合），例如Array时
     * 如果对Array中的元素进行修改 并不会影响变量的指向
     * 只要变量的指向不变，就可以认为是不可变的，即可以使用val进行修饰
     */

    val arr: Array[Int] = Array[Int](1, 2, 3, 4, 5, 6, 7)

    println(arr(3))

    arr(3) = 44

    println(arr(3))

    // Scala中的注释  同 Java一致
    // 一行注释
    /*
    多行注释
     */
    /**
     * 文档注释
     */

    // println函数
    println() // 底层还是采用Java的sout进行输出，Scala在这之上做了封装，简化了调用

    /**
     * Scala中的基本数据类型：八大基本数据类型，类似Java
     * Java中有八大基本数据类型：byte、short、int、long、float、double、boolean、char
     * Java中的基本数据类型首字母大写即形成了Scala中的基本数据类型
     */

    val byte: Byte = 10
    val short: Short = 256
    val int: Int = 1000
    val long: Long = 10000000L

    val float: Float = 1.1F
    val double: Double = 1.1D

    val boolean1: Boolean = true
    val boolean2: Boolean = false

    val char: Char = 'a'

    /**
     * String 是引用类型，不算做基本数据类型
     * Scala中的String类型实际上是Java中的
     * Java中的String类型有的方法同样在Scala适用
     * 同时Scala还拥有额外的跟字符串相关的方法（通过隐式转换implicit让字符串获得额外的方法）
     */

    val str: String = "abcdefg" // 可以看成一个字符数组
    println(str)
    // 提取str中的cd
    println(str.substring(2, 4))

    val str2: String = "Java,Python,Scala"
    val strArr: Array[String] = str2.split(",")
    println(strArr)

    println(str.head) // 取第一个字符
    println(str.tail) // 取除第一个字符之外的所有字符
    println(str.take(2)) // 取前n个字符
    println(str.max) // 返回编码大的字符
    println(str.min) // 返回编码小的字符
    // ......

    // 不同数据类型直接的转换
    // 直接to对应的类型即可
    val str3: String = "12345"
    // 将字符串转为Int类型
    // Java中的方式
    println(Integer.parseInt(str3))
    // Scala中的方式
    println(str3.toInt)
    println(str3.toLong)
    println(str3.toDouble)

    val ii: Int = 98765
    // 将Int类型转换成其他类型
    println(ii.toLong)
    println(ii.toShort)
    println(ii.toDouble)
    println(ii.toChar)

    // 拼接字符串 通过 | 拼接
    val s1: String = "Hadoop"
    val s2: String = "Hive"
    val s3: String = "HBase"
    val _s4: String = "Spark"

    val sp: String = "|"

    // 直接使用+
    println(s1 + sp + s2 + sp + s3 + sp + _s4)

    // 使用StringBuilder
    val builder = new StringBuilder()
    builder.append(s1)
    builder.append(sp)
    builder.append(s2)
    builder.append(sp)
    builder.append(s3)
    builder.append(sp)
    builder.append(_s4)
    println(builder)

    // Scala中拼接字符串
    // 使用s修饰字符串，注意：如果变量名以下划线开头，则需要使用花括号括起来
    println(s"$s1|$s2|$s3|${_s4}")

    /**
     * 原生的字符串写法不适合换行
     */
    val sqlStr1: String = "select id" +
      ",name" +
      ",age " +
      "from student " +
      "where clazz = '文科一班'"

    val sqlStr2: String =
      """
        |select id
        |       ,name
        |       ,age
        |from student
        |where clazz = '文科一班'
        |""".stripMargin

    // 算数运算
    val p: Int = 10
    val q: Int = 3
    println(p + q)
    println(p - q)
    println(p * q)
    println(p / q) // 两个Int相除会向下取整
    println(p / q.toDouble)
    println(p % q) // 取余数

    // 输出50个#号
    println("##################################################")
    println("#" * 50) // 调用字符串的方法 方法名为*
    println("#".*(50)) // 完整的调用形式

    // Scala中函数的调用可以省略
    val helloJava = new HelloJava()
    helloJava.printHello("xiaohong")

    helloJava printHello "xiaohong" // 最好不用 可读性较差

    // 逻辑运算
    val b1: Boolean = true
    val b2: Boolean = false

    // 与 或 异或 非
    println(b1 & b2)
    println(b1 | b2)
    println(b1 ^ b2)
    println(!b1)

    /**
     * 读文件
     */

    /**
     * Java的方式
     */
    val bufferedReader: BufferedReader = new BufferedReader(new FileReader("scala/data/words.txt"))
    var line: String = bufferedReader.readLine()
    while (line != null) {
      println(line)
      line = bufferedReader.readLine()
    }

    println("#" * 50)

    /**
     * Scala的方式
     */
    val bs: BufferedSource = Source.fromFile("scala/data/words.txt")
    val iter: Iterator[String] = bs.getLines()
    val list: List[String] = iter.toList
    for (line <- list) {
      println(line)
    }
    println("#" * 50)

    def printLine(name: String): Unit = {
      println(name)
    }

    // 运用函数式编程的思想
    list.foreach(printLine)
    println("#" * 50)
    list.foreach(println)
    // 关闭文件
    bs.close()
    println("#" * 50)
    // 简化版：链式调用
    val bs2: BufferedSource = Source
      .fromFile("scala/data/words.txt")

    bs2
      .getLines()
      .toList
      .foreach(println)
    // 关闭文件
    bs2.close()

    /**
     * Scala中无特殊的写文件方式 参考Java中写文件即可
     * FileWriter
     * PrintWriter
     */


    /**
     * 读MySQL数据库
     * host:rm-bp1h7v927zia3t8iwho.mysql.rds.aliyuncs.com
     * port:3307
     * user:shujia21
     * password:123456
     * db:city_crm_21
     */
    // Scala中也没有特殊的连接MySQL的方式，可以直接使用JDBC读取MySQL

    // 查询文科班的学生
    val clazz: String = "文科"
    // 1、建立链接
    val conn: Connection = DriverManager.getConnection("jdbc:mysql://rm-bp1h7v927zia3t8iwho.mysql.rds.aliyuncs.com:3307/city_crm_21?useSSL=false", "shujia21", "123456")

    // 2、创建statement
    val pSt: PreparedStatement = conn.prepareStatement(
      """
        |select id
        |       ,name
        |       ,age
        |       ,gender
        |       ,clazz
        |from students
        |where clazz like concat(?,'%')
        |""".stripMargin)

    // 3、设置参数
    pSt.setString(1, clazz)

    // 4、执行SQL
    val rs: ResultSet = pSt.executeQuery()

    // 5、遍历ResultSet获取数据
    while (rs.next()) {
      val id: Long = rs.getLong("id")
      val name: String = rs.getString("name")
      val age: Long = rs.getLong("age")
      val gender: String = rs.getString("gender")
      val clazz: String = rs.getString("clazz")

      println(s"$id,$name,$age,$gender,$clazz")
    }

    // 6、关闭链接
    rs.close()
    pSt.close()
    conn.close()


    // Scala中的数组
    val intArr: Array[Int] = Array[Int](1, 2, 3, 4, 5, 6, 7)
    // 遍历数组
    for (elem <- intArr) {
      println(elem)
    }

    intArr.foreach(println)

    // 构建序列
    for (i <- 0 to intArr.length - 1) {
      println(intArr(i))
    }

    for (i <- 0 until intArr.length) {
      println(intArr(i))
    }

    for (i <- Range(0, 7, 1)) {
      println(intArr(i))
    }

    // 选择结构同Java一致
    val age: Int = 10
    if (age >= 18) {
      println("成年人")
    } else if (age >= 0) {
      println("未成年人")
    } else {
      println("错误的年龄")
    }

    // 循环结构：主要指while循环，for循环主要用于遍历数据容器，Scala中没有for i的循环
    // 计算1~100的和
    var c: Int = 1
    var sum: Int = 0
    while (c <= 100) {
      sum += c // Scala中无++ --这类操作
      c += 1
    }
    println(sum)

    // do while
    var cnt: Int = 1
    var res: Int = 0
    do {
      res += cnt
      cnt += 1
    } while (cnt <= 100)

    println(res)


  }

}
